package com.aviator.executor;

import com.googlecode.aviator.AviatorEvaluator;

import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * @Author: Jiangxx
 * @Date: 2021/12/30
 * @Description: 大数计算和精度：从 2.3.0 版本开始,aviator 开始支持大数字计算和特定精度的计算,
 * 本质上就是支持java.math.BigInteger和java.math.BigDecimal两种类型, 这两种类型在 aviator 中简称 为big int和decimal类型。
 * 类似99999999999999999999999999999999这样的数字在 Java 语言里是没办法编译通过 的, 因为它超过了Long类型的范围,
 * 只能用BigInteger来封装。但是 aviator 通过包装,可 以直接支持这种大整数的计算
 */
public class AviatorExecutor10 {


    public static void main(String[] args) {
        System.out.println(AviatorEvaluator.exec("99999999999999999999999999999999 + 99999999999999999999999999999999"));

        /**
         * 字面量表示：big int和decimal的表示与其他数字不同,两条规则:
         * 以大写字母N为后缀的整数都被认为是big int,如1N,2N,9999999999999999999999N等, 都是big int类型。
         * 超过long范围的整数字面量都将自动转换为big int类型。
         * 以大写字母M为后缀的数字都被认为是decimal, 如1M,2.222M, 100000.9999M等, 都是decimal类型。
         * 用户也可以通过变量传入这两种类型来参与计算。
         * 如果用户觉的给浮点数添加 M 后缀比较繁琐，也可以强制所有浮点数解析为 BigDecimal，通过代码开启下列选项即可：
         * AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, true);
         */

        /**
         * 运算：big int和decimal的运算,跟其他数字类型long,double没有什么区别,操作符仍然是一样的。
         * aviator重载了基本算术操作符来支持这两种新类型:
         */
        Object rt = AviatorEvaluator.exec("9223372036854775807100.356M * 2");
        System.out.println(rt + " " + rt.getClass());  // 18446744073709551614200.712 class java.math.BigDecimal
        rt = AviatorEvaluator.exec("92233720368547758074+1000");
        System.out.println(rt + " " + rt.getClass());  // 92233720368547759074 class java.math.BigInteger
        BigInteger a = new BigInteger(String.valueOf(Long.MAX_VALUE) + String.valueOf(Long.MAX_VALUE));
        BigDecimal b = new BigDecimal("3.2");
        BigDecimal c = new BigDecimal("9999.99999");
        rt = AviatorEvaluator.exec("a+10000000000000000000", a);
        System.out.println(rt + " " + rt.getClass());  // 92233720368547758089223372036854775807 class java.math.BigInteger
        rt = AviatorEvaluator.exec("b+c*2", b, c);
        System.out.println(rt + " " + rt.getClass());  // 20003.19998 class java.math.BigDecimal
        rt = AviatorEvaluator.exec("a*b/c", a, b, c);
        System.out.println(rt + " " + rt.getClass());  // 2.951479054745007313280155218459508E+34 class java.math.BigDecimal

        /**
         * 类型转换和提升：当big int或者decimal和其他类型的数字做运算的时候,按照long < big int < decimal < double的规则做提升, 也就是说运算的数字如果类型不一致, 结果的类型为两者之间更“高”的类型。例如:
         *
         * ● 1 + 3N, 结果为big int的4N
         * ● 1 + 3.1M,结果为decimal的4.1M
         * ● 1N + 3.1M,结果为decimal的 4.1M
         * ● 1.0 + 3N,结果为double的4.0
         * ● 1.0 + 3.1M,结果为double的4.1
         */

        /**
         * Java 的java.math.BigDecimal通过java.math.MathContext支持特定精度的计算,
         * 任何涉及到金额的计算都应该使用decimal类型。
         *
         * 默认 Aviator 的计算精度为MathContext.DECIMAL128,你可以自定义精度, 通过:
         * AviatorEvaluator.setOption(Options.MATH_CONTEXT, MathContext.DECIMAL64);
         */
    }
}
